﻿using System;

//This namespace is needed for saving the Task as OutlookTask
using Outlook = Microsoft.Office.Interop.Outlook;
using System.Runtime.InteropServices;

namespace TaskBoardProject
{
    /// <summary>
    /// This class provides some
    /// Outlook integration features like:
    /// export Tasks to Outlook.
    /// Also it implements IDisposable to release unmanaged resources,
    /// such as Outlook.Application.
    /// </summary>
    public sealed class OutlookService : IDisposable
    {
        //Declaration of Outlook.Application instance, that initializing in default constructor
        Outlook.Application outlookApp;

        /// <summary>
        /// Default constructor
        /// </summary>
        public OutlookService()
        {
            outlookApp = new Outlook.Application();
        }


        /// <summary>
        /// This method provide possibility to save Task as OutlookTask
        /// </summary>
        /// <param name="taskToSave">Represents an instance of Task, that will be saved</param>
        public void SaveAsOutlookTask(Task taskToSave)
        {
            Outlook.TaskItem outlookTask = null;
            try
            {
                outlookTask = outlookApp.CreateItem(Outlook.OlItemType.olTaskItem) as Outlook.TaskItem;
                outlookTask.Subject = String.Format("{0} => {1}", taskToSave.ProjectName, taskToSave.TaskName);
                outlookTask.StartDate = taskToSave.TimeFrom;
                outlookTask.DueDate = taskToSave.TimeTo;
                outlookTask.ReminderSet = false;
                outlookTask.Body = taskToSave.TaskDescription;
                outlookTask.Importance = ConvertPriorityToImportance(taskToSave.TaskPriority);
                outlookTask.Status = Microsoft.Office.Interop.Outlook.OlTaskStatus.olTaskInProgress;
                outlookTask.Owner = taskToSave.AssignedEmploye;
                outlookTask.Save();
                outlookTask.Display(false);
                Console.WriteLine("Export {0} to Outlook *.msg-file was succefull!", taskToSave.TaskName);
            }
            catch (NullReferenceException)
            {
                Console.WriteLine("No Outlook application instance. Export to Outlook *.msg-file was failed!");
                return;
            }
            finally
            {
                if (outlookTask != null) Marshal.ReleaseComObject(outlookTask);
                outlookTask = null;
            }

        }

        /// <summary>
        /// This method provide possibility to load OutlookTask by Subject
        /// It get default task folder of default user.
        /// The loaded task is converting to instance of class Task
        /// </summary>
        /// <returns> Method returns an instance of object Task </returns>
        public Task GetOutlookTaskBySubjet()
        {

            Outlook._NameSpace outlookNamespace = null;
            Outlook.TaskItem item = null;
            Outlook.MAPIFolder inboxFolder = null;
            string taskName = "";
            Task taskFromOutlook = null;

            // The block try/catch/finally handle some errors, such as:
            // declaration/initialization Outlook object's errors,
            // declaration/initialization Task instance's errors.
            // Block finally provides releasing of unmanaged resources.
            try
            {
                outlookApp = new Microsoft.Office.Interop.Outlook.Application();
                outlookNamespace = outlookApp.GetNamespace("MAPI");
                outlookNamespace.Logon(null, null, false, false);

                inboxFolder = outlookNamespace.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderTasks);

                Console.WriteLine("Outlook default task folder name: {0}", inboxFolder.Name);
                Console.Write("Enter task name that you want to import: ");
                taskName = Console.ReadLine();

                for (int i = 1; i <= inboxFolder.Items.Count; i++)
                {
                    item = (Microsoft.Office.Interop.Outlook.TaskItem)inboxFolder.Items[i];

                    if (taskName == item.Subject)
                    {
                        taskFromOutlook = new Task("Default", item.Subject, item.Body,
                            ConvertImportanceToPriority(item.Importance),
                            item.StartDate, item.DueDate, CheckAsignEmployeeString(item.Owner));
                        Console.WriteLine("Task {0} was succesfully imported!", item.Subject);
                        break;
                    }
                }

                if (taskFromOutlook == null)
                {
                    Console.WriteLine("No such task in Outlook default task folder.");
                }
            }
            catch (System.Runtime.InteropServices.COMException comEx)
            {
                Console.WriteLine(comEx.ToString());
                taskFromOutlook = null;
            }
            catch (NullReferenceException nrEx)
            {
                Console.WriteLine("There was an error while creating new instance of Task!");
                taskFromOutlook = null;
            }
            finally
            {
                if (outlookNamespace != null) Marshal.ReleaseComObject(outlookNamespace);
                if (inboxFolder != null) Marshal.ReleaseComObject(inboxFolder);
                if (item != null) Marshal.ReleaseComObject(item);
                outlookNamespace = null;
                inboxFolder = null;
                item = null;
            }
            return taskFromOutlook;
        }


        /// <summary>
        /// Modified Dispose Pattern. 
        /// It hasn't maethod Dispose(bool disposing), because
        /// class don't have managed resources
        /// </summary>
        private bool disposed = false;

        public void Dispose()
        {
            CloseOutlookService();
            GC.SuppressFinalize(this);
        }

        private void CloseOutlookService()
        {
            if (disposed) return;
            // release unmanaged memory
            if (outlookApp != null)
            {
                Marshal.ReleaseComObject(outlookApp);
            }

            disposed = true;
        }

        ~OutlookService()
        {
            CloseOutlookService();
        }


        /// <summary>
        /// Method check number of words in input string and 
        /// return correct format of Person Name, which
        /// consists of First and Second Name
        /// </summary>
        /// <param name="taskOwner">the checking string</param>
        /// <returns>the correct string, that represents Task Owner Name</returns>
        private string CheckAsignEmployeeString(string taskOwner)
        {
            if (taskOwner.Length <= 0)
            {
                return "Undefined Owner";
            }
            else
            {
                string[] splittedStringArray = taskOwner.Split(' ');
                if (splittedStringArray.Length == 1)
                {
                    return String.Format("{0} Undefined", taskOwner);
                }
                else
                {
                    return taskOwner;
                }
            }
        }


        /// <summary>
        /// This method return converted value 
        /// from Outlook Task Importance field to value of enum TaskPriority 
        /// </summary>
        /// <param name="importance">Represents instance of Outlook.OlImportance</param>
        /// <returns> A value of enum TaskPriority </returns>
        private TaskPriority ConvertImportanceToPriority(Outlook.OlImportance importance)
        {
            switch (importance)
            {
                case Outlook.OlImportance.olImportanceHigh:
                    return TaskPriority.High;
                case Outlook.OlImportance.olImportanceLow:
                    return TaskPriority.Low;
                case Outlook.OlImportance.olImportanceNormal:
                    return TaskPriority.Medium;
                default:
                    return TaskPriority.Low;
            }
        }

        /// <summary>
        /// This method return converted value 
        /// from value of enum TaskPriority to Outlook Task Importance field
        /// </summary>
        /// <param name="priority">Represents a value of enum of TaskPriority</param>
        /// <returns> an Outlook Task Importance field </returns>
        private Outlook.OlImportance ConvertPriorityToImportance(TaskPriority priority)
        {
            switch (priority)
            {
                case TaskPriority.High:
                    return Outlook.OlImportance.olImportanceHigh;
                case TaskPriority.Medium:
                    return Outlook.OlImportance.olImportanceNormal;
                case TaskPriority.Low:
                    return Outlook.OlImportance.olImportanceLow;
                default:
                    return Outlook.OlImportance.olImportanceLow;
            }
        }

    }
}
